--[[ - Created by Tronex - Bounty squads - 2018/10/13 - created - on high ranks or really bad repuation, your enemies will put a bounty on your head. - every while and then, one of the enemy factions will send a hit squad to hunt you down. --]] --==========================================< Controls >==========================================-- local active_squads = {} -- current active bounty squads local delay = 60*60*24 -- game seconds local delay_spawn = 300 --300 -- real seconds local delay_state = 10 -- real seconds local delta = 60*60 -- not used for now local spawn_distance = 200 -- don't spawn bounty squads below this distance local last_spawn_time -- the last time an bounty squad has been spawned local factions = {} -- List of factions that can send bounty squads local safe_levels = {} -- bounty squad will stop targeting the player if he's in one of those maps local safe_smarts = {} -- bounty squad will stop targeting the player if he's in one of those smarts local faction_bounty_squads = {} -- bounty squad section local danger_ranks = {} -- player ranks and the number of possible bounty squad to spawn when a rank is met local danger_reputations = {} -- player reputations and the number of possible bounty squad to spawn when a reputation is met --====================================< Utilities >====================================-- function try_spawn() -- gather factions local enemy_factions = {} for i=1,#factions do if game_relations.is_factions_enemies(factions[i],db.actor:character_community()) then enemy_factions[#enemy_factions + 1] = factions[i] --printf("-bounty_squads.try_spawn / [%s] is a possible faction",factions[i]) end end local picked_squad = enemy_factions[math.random(#enemy_factions)] -- gather smarts local spawn_smrt local spawn_smrts = {} for name,smart in pairs( SIMBOARD.smarts_by_names ) do local dist = smart.position:distance_to(db.actor:position()) if (dist > spawn_distance) and (simulation_objects.is_on_the_same_level(alife():actor(), smart) or simulation_objects.is_on_the_linked_level(alife():actor(), smart)) then local smrt = SIMBOARD.smarts[smart.id] if ( smrt ) then local pass = true for k,v in pairs( smrt.squads ) do local squad = alife_object(k) if (squad and squad.current_target_id and squad.current_target_id == smart.id and not squad:get_script_target()) then pass = false break end end if pass then --printf("-bounty_squads.try_spawn / [%s] is a possible smart found, distance: %s",name,dist) spawn_smrts[#spawn_smrts+1] = name end end end end if (#spawn_smrts > 0) then spawn_smrt = spawn_smrts[math.random(#spawn_smrts)] printdbg("- bounty_squads.try_spawn / [%s] has been spawned in [%s]", faction_bounty_squads[picked_squad], spawn_smrt) -- Spawn squad and target the player local sq = sim_board.get_sim_board():create_squad(SIMBOARD.smarts_by_names[spawn_smrt], faction_bounty_squads[picked_squad]) sq.scripted_target = "actor" sq.rush_to_target = true active_squads[sq.id] = sq:section_name() last_spawn_time = game.get_game_time() end end function attack(state) for k,v in pairs(active_squads) do local se = alife_object(k) if se and (se:section_name() == v) then se.scripted_target = state and "actor" or nil se.rush_to_target = state and true or false --printf("-bounty_squads.attack - target: %s - rush: %s",se.scripted_target,se.rush_to_target) end end end function check_close_squads(sq) for k,v in pairs(active_squads) do local se = alife_object(k) if se and (se:section_name() == v) and (simulation_objects.is_on_the_same_level(alife():actor(), se)) then for j in se:squad_members() do local npc = db.storage[j.id] and db.storage[j.id].object if npc and npc:alive() then return true end end end end return false end function get_active_squads() return active_squads end function tbl_size(tbl) local n = 0 for k,v in pairs(tbl) do n = n + 1 end return n end --====================================< Callbacks >====================================-- function spawn_timer() --printf("-bounty_squads.spawn_timer called") ResetTimeEvent("cycle","bounty_squad_spawn",delay_spawn) local num = 0 -- check rank local rank = ranks.get_obj_rank_name(db.actor) if danger_ranks[rank] then num = num + danger_ranks[rank] end -- check reputaion local reputaion = utils_obj.get_reputation_name(db.actor:character_reputation()) if danger_reputations[reputaion] then num = num + danger_reputations[reputaion] end -- ignore if rank or rep doesn't meet the requirements if (num == 0) then return false end -- read date local current_time = game.get_game_time() if (not last_spawn_time) then last_spawn_time = current_time return false end -- ignore if timer hasn't been reached yet if (current_time:diffSec(last_spawn_time) < delay) then return false end -- try to spawn if there isn't enough bounty squads if (tbl_size(active_squads) < num) then try_spawn() end return false end function state_timer() --printf("-bounty_squads.state_timer called") ResetTimeEvent("cycle","bounty_squad_state",delay_state) -- clean for k,v in pairs(active_squads) do local se = alife_object(k) if se and (se:section_name() ~= v) then --printf("-bounty_squads.state_timer cleaning [%s] | section: %s - v: %s",k,se:section_name(),v) --safe_release_manager.release(se) active_squads[k] = nil elseif (not se) then --printf("-bounty_squads.state_timer cleaning [%s] | no alife object found",k) active_squads[k] = nil end end if (tbl_size(active_squads) == 0) then return false end -- don't attack if actor is in a safe level if safe_levels[level.name()] then attack(false) return false end -- don't attack if actor is in a safe smart local pos = db.actor:position() local se_actor = alife():actor() for name,smart in pairs( SIMBOARD.smarts_by_names ) do local dist = smart.position:distance_to(pos) if (dist < 40) and simulation_objects.is_on_the_same_level(se_actor, smart) then if safe_smarts[name] then attack(false) return false end end end attack(true) return false end local function load_state(m_data) local bounty_squad = m_data.bounty_squad if (not bounty_squad) then return end if DEV_DEBUG and bounty_squad then for k,v in pairs(bounty_squad) do printdbg("# LOADING: Bounty Squad | [%s]: %s", k, v) end end last_spawn_time = bounty_squad.last_spawn_time and utils_data.CTime_from_table(bounty_squad.last_spawn_time) or game.get_game_time() active_squads = bounty_squad.active_squads or {} end local function save_state(m_data) if (not last_spawn_time) then return end local bounty_squad = {} bounty_squad.last_spawn_time = utils_data.CTime_to_table(last_spawn_time) bounty_squad.active_squads = active_squads or {} if DEV_DEBUG then for k,v in pairs(bounty_squad) do printdbg("# SAVING: Bounty Squad | [%s]: %s", k, v) end end m_data.bounty_squad = bounty_squad end local function server_entity_on_unregister(se_obj, typ) active_squads[se_obj.id] = nil end function on_game_start() local ini_bounty_squad = ini_file("plugins\\bounty_squad.ltx") local n = 0 n = ini_bounty_squad:line_count("faction_list") for i=0,n-1 do local result, id, value = ini_bounty_squad:r_line_ex("faction_list",i,"","") if id then factions[#factions + 1] = id end end n = ini_bounty_squad:line_count("safe_levels") for i=0,n-1 do local result, id, value = ini_bounty_squad:r_line_ex("safe_levels",i,"","") if id then safe_levels[id] = true end end n = ini_bounty_squad:line_count("safe_smarts") for i=0,n-1 do local result, id, value = ini_bounty_squad:r_line_ex("safe_smarts",i,"","") if id then safe_smarts[id] = true end end n = ini_bounty_squad:line_count("faction_bounty_squads") for i=0,n-1 do local result, id, value = ini_bounty_squad:r_line_ex("faction_bounty_squads",i,"","") if id and value then faction_bounty_squads[id] = value end end n = ini_bounty_squad:line_count("danger_ranks") for i=0,n-1 do local result, id, value = ini_bounty_squad:r_line_ex("danger_ranks",i,"","") if id and value then danger_ranks[id] = tonumber(value) or 0 end end n = ini_bounty_squad:line_count("danger_reputations") for i=0,n-1 do local result, id, value = ini_bounty_squad:r_line_ex("danger_reputations",i,"","") if id and value then danger_reputations[id] = tonumber(value) or 0 end end local function on_game_load() CreateTimeEvent("cycle","bounty_squad_spawn",delay_spawn,spawn_timer) CreateTimeEvent("cycle","bounty_squad_state",delay_state,state_timer) end RegisterScriptCallback("save_state",save_state) RegisterScriptCallback("load_state",load_state) RegisterScriptCallback("on_game_load",on_game_load) RegisterScriptCallback("server_entity_on_unregister",server_entity_on_unregister) end